package ua.edu.sumdu.j2se.roman.lab1.controller;

import ua.edu.sumdu.j2se.roman.lab1.domain.Task;
import ua.edu.sumdu.j2se.roman.lab1.domain.TaskList;
import ua.edu.sumdu.j2se.roman.lab1.exceptions.FileSerializationException;
import ua.edu.sumdu.j2se.roman.lab1.model.TasksModel;
import ua.edu.sumdu.j2se.roman.lab1.model.TasksModelImpl;
import ua.edu.sumdu.j2se.roman.lab1.util.Log;
import ua.edu.sumdu.j2se.roman.lab1.view.*;
import ua.edu.sumdu.j2se.roman.lab1.view.console.*;
import ua.edu.sumdu.j2se.roman.lab1.view.swing.SwingPostponeCommandView;
import ua.edu.sumdu.j2se.roman.lab1.view.swing.SwingPostponeView;
import ua.edu.sumdu.j2se.roman.lab1.view.swing.SwingReminderView;

import java.util.Date;
/**
 * Author: Radko Roman.
 */

/**
 * Method main create controller object. In the infinity cycle controller check command, entered by user
 * (using ConsoleEnteredCommand object). When command get from user (as a string), this command parse and
 * execute (by calling appropriate view from console package).
 * At the same time status of the model (tasks storage) is under the observation of the RemindTimer object
 * (when status of the model is change (add, delete or edit command is choose) the RemindTimer object
 * get corresponding notification, by calling update() method).
 *
 */
public class ManagerController implements Controller{

    public static final String ADD_COMMAND = "add";
    public static final String DELETE_COMMAND = "delete";
    public static final String LIST_COMMAND = "list";
    public static final String CLOSE_COMMAND = "close";
    public static final String POSTPONE_COMMAND = "postpone";
    public static final int NO_ERRORS = 0;
    private ReminderView reminderView;
    private TasksModel model;
    private RemindTimer remindTimer;
    private EnterCommandView enterCommandView;
    private AddView addView;
    private ListView listView;
    private DeleteView deleteView;
    private ErrorMessageView errorMessageView;
    private PostponeCommandView postponeCommandView;
    private PostponeView postponeView;
    private InformMassage informMassage;

    /**
     * This default constructor starting interface interaction with user in a separate thread.
     *
     */
    public ManagerController() {
        init();
    }

    /**
     * Initialize all component of the application.
     *
     */
    private void init() {
        enterCommandView = new ConsoleEnterCommandView();
        model = new TasksModelImpl();
        remindTimer = new RemindTimer(this, model);
        reminderView = new SwingReminderView();
        addView = new ConsoleAddView();
        listView = new ConsoleListView();
        deleteView = new ConsoleDeleteView();
        errorMessageView = new ConsoleErrorMessageView();
        postponeCommandView = new SwingPostponeCommandView(this);
        postponeView = new SwingPostponeView();
        informMassage = new ConsoleInfoMassage();
    }

    public static void main(String[] args) {
        Controller managerController = new ManagerController();
        managerController.getInformMassage().show("Enter your command (add/delete/list/close):");
        
        while (true) {
            EnterCommandView dialogWithUser = managerController.getEnterCommandFromConsoleView();
            dialogWithUser.show();
            String enteredCommand = dialogWithUser.getEnteredCommand();
            managerController.performAction(enteredCommand);
            
        }
    }

    /**
     * Gets reference that refer to the get next command dialog.
     *
     * @return inform massage
     */
    @Override
    public InformMassage getInformMassage() {
        return informMassage;
    }
    /**
     * Gets entered command by user from console.
     *
     * @return entered command
     */
    @Override
    public EnterCommandView getEnterCommandFromConsoleView() {
        return enterCommandView;
    }
    /**
     * Start notification of task.
     *
     * @param tasks set of tasks
     */
    @Override
    public void tasksTimeBecomeEvent(TaskList tasks) {
        Log.i("Tasks time fired:");
        for(Task t : tasks) {
            Log.i(t.toString());
        }
        for (Task t :tasks) {
            reminderView.show(t);
        }
    }

    /**
     * Saves all task in task journal before exit and close application.
     *
     */
    @Override
    public void chooseCloseCommand() {
        try {
            model.saveData();
        } catch (FileSerializationException e) {
            String msg = "Can not save data. Data will not be saved.";
            Log.e(msg, e);
            errorMessageView.show(msg);            
            throw new RuntimeException(msg,e);
        }
        System.exit(NO_ERRORS);
    }
    /**
     * Adds new task to the task list.
     *
     */
    @Override
    public void chooseAddCommand() {
        addView.show();
        Date startDateOfAddedTask = addView.getStartDateOfAddedTask();
        String titleOfTheAddedTask = addView.getTitleOfAddedTask();
        Task addedTask = createNewTask(titleOfTheAddedTask, startDateOfAddedTask);
        addTask(addedTask);
        informMassage.show("Task [" + addedTask + "] successfully added:");
        informMassage.show(("========================================================="));
    }
    
    /**
     * Open delete view.
     *
     */
    @Override
    public void chooseDeleteCommand() {
        deleteView.show();
        String titleOfTheDeletingTask = deleteView.getTitleOfTheDeletingTask();
        if (deleteTask(titleOfTheDeletingTask)) {
            informMassage.show("Task successfully deleted from the list.");
        } else {
            informMassage.show("There is no task with [" + titleOfTheDeletingTask + "] such title in list.");
        }
        informMassage.show(("========================================================="));
    }
    
    /**
     * Get all task from the model and show it on the list view.
     *
     */
    @Override
    public void chooseListCommand() {
        TaskList tasks = model.getTasks();
        listView.show(tasks);
        informMassage.show(("========================================================="));
    }
    /**
     * Open postpone view.
     *
     * @param task postponed task
     */
    @Override
    public void choosePostponeCommand(Task task) {
        Log.i("Check entering in the postpone view");
        postponeCommandView.show(task);
        Date nextTime = postponeCommandView.getNextDateOfPostponeTaskNotification();
        postponeTask(task,nextTime);
        informMassage.show("Task: [" + task + "] successfully postponed.");
        informMassage.show(("========================================================="));
    }
    
    /**
     * Add task to the task list.
     *
     * @param task  to be added
     */
    @Override
    public void addTask(Task task) {
        model.addTask(task);
    }
    /**
     * Creates task with entered parameters.
     *
     * @param title     of the task
     * @param startTime time when task must be declared
     * @return          new task
     */
    @Override
    public Task createNewTask(String title, Date startTime) {
        Task newTask = new Task(title, startTime);
        return newTask;
    }

    /**
     * Deleted the task by title.
     *
     * @param title of the removing task
     * @return  delete or not
     */
    @Override
    public boolean deleteTask(String title) {
        Task task = model.getTaskByTitle(title);
        if (task != null) {
            model.deleteTask(task);
            return true;
        }
        return false;
    }

    @Override
    /**
     * Inform controller about entered command.
     *
     * @param command   from the console
     */
    public void performAction(String command) {
        Log.i("Command entered: [ " + command + " ]");
        command = command.toLowerCase();
        if (command.equals(ADD_COMMAND)) {
            chooseAddCommand();
        } else if (command.equals(DELETE_COMMAND)) {
            chooseDeleteCommand();
        } else if (command.equals(CLOSE_COMMAND)) {
            chooseCloseCommand();
        } else if (command.equals(LIST_COMMAND)) {
            chooseListCommand();
        }

    }

    /**
     * Close postpone view.
     *
     */
    @Override
    public void onPostponeViewClose() {
        enterCommandView.show();
    }


    /**
     * Inform about user choice when need to postpone or close warning task.
     *
     * @param command    close or postpone
     * @param remindTask task planned at some time
     */
    @Override
    public void performRemindAction(String command, Task remindTask) {
        if (command.toLowerCase().equals(CLOSE_COMMAND)) {
            Log.i("Action performed [" + CLOSE_COMMAND + "]");
            onPostponeViewClose();
        } else if (command.toLowerCase().equals(POSTPONE_COMMAND)) {
            Log.i("Action performed [" + POSTPONE_COMMAND + "]");
            choosePostponeCommand(remindTask);
        } else {
            Log.e("Wrong command: [" + command + "]");
        }
    }

    /**
     * Postpone task for next time.
     *
     * @param task     postponed task
     * @param nextTime date of the next notification
     */
    @Override
    public void postponeTask(Task task, Date nextTime) {
        model.postponeTask(task, nextTime);
    }

}

